package com.egreen.alipay.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayFundAccountQueryModel;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.egreen.alipay.service.AlipayService;
import com.egreen.common.Result;
import com.egreen.common.States;
import com.egreen.common.pojo.VO.alipay.AlipayUserInfoVO;
import com.egreen.common.pojo.DTO.asset.BalanceAccountDTO;
import com.egreen.common.pojo.DTO.asset.OperateBalanceRecordingDTO;
import com.egreen.common.serviceapi.asset.IAssetServiceApi;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import static com.egreen.alipay.config.AlipayConfig.getCertAlipayRequest;


/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author volcan
 * @since 2022-07-22
 */
@Slf4j
@Service
public class AlipayServiceImpl implements AlipayService {
    @DubboReference
    private IAssetServiceApi iAssetServiceApi;


    //更新用户信息
    @Override
    public Result getAlipayUserInfo(HttpServletRequest request) throws AlipayApiException {
        String authCode = request.getParameter("auth_code");

        AlipayClient alipayClient = new DefaultAlipayClient(getCertAlipayRequest());
        AlipayUserInfoShareRequest userInfoRequest = new AlipayUserInfoShareRequest();
        AlipaySystemOauthTokenRequest oauthTokenRequest = new AlipaySystemOauthTokenRequest();

        oauthTokenRequest.setGrantType("authorization_code");
        oauthTokenRequest.setCode(authCode);
        AlipaySystemOauthTokenResponse response = alipayClient.certificateExecute(oauthTokenRequest);

        AlipayUserInfoVO alipayUserInfoVO = new AlipayUserInfoVO();

        if (response.isSuccess()) {
            log.info("获取授权令牌access_token成功");
            String accessToken = response.getAccessToken();
            AlipayUserInfoShareResponse userInfoResponse = alipayClient.certificateExecute(userInfoRequest, accessToken);
            if (!userInfoResponse.isSuccess()) {
                log.info("支付宝调用AlipaySDK获取用户信息失败");
                return Result.Error(States.ERR_ALIPAY_SERVER);
            }else{
                log.info("支付宝调用AlipaySDK获取用户信息成功");
                alipayUserInfoVO.setAlipayUserId(userInfoResponse.getUserId());
                alipayUserInfoVO.setAlipayUserAvatar(userInfoResponse.getAvatar());
                alipayUserInfoVO.setAlipayUserNickname(userInfoResponse.getNickName());
            }
        }else {
            log.info("获取授权令牌access_token失败");
            return Result.Error(States.ERR_ALIPAY_ACCESSTOKEN);
        }
        return Result.OK(alipayUserInfoVO);
    }

    @Override
    public Result bindAlipayUserInfo(HttpServletRequest request){
        Integer balanceAccountId = Integer.valueOf(request.getParameter("id"));
        String alipayUserId = request.getParameter("alipayUserId");
        String alipayUserAvatar = request.getParameter("alipayUserAvatar");
        String alipayUserNickname = request.getParameter("alipayUserNickname");
        BalanceAccountDTO balanceAccountDTO = iAssetServiceApi.selectBalanceAccountById(balanceAccountId);
        if (balanceAccountDTO == null){
            log.info("取出用户信息失败");
            return Result.Error(States.ERR_SELECT);
        }else {
            log.info("取出用户信息成功");
            balanceAccountDTO.setIdentity(alipayUserId);
            balanceAccountDTO.setAvatar(alipayUserAvatar);
            balanceAccountDTO.setNickName(alipayUserNickname);
            int i = iAssetServiceApi.updateAlipayAccount(balanceAccountDTO);
            if (i != 1){
                log.info("数据插入失败");
                return Result.Error(States.ERR_UPDATE);
            }
        }
        log.info("绑定支付宝信息成功");
        return Result.OK();
    }

    @Override
    public Result transfer(String transAmount,int balanceAccountId) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient(getCertAlipayRequest());
        AlipayFundAccountQueryRequest queryRequest = new AlipayFundAccountQueryRequest();
        AlipayFundAccountQueryModel model = new AlipayFundAccountQueryModel();
        model.setAlipayUserId("2088621987431214");//查询余额所用的商家appid
        model.setAccountType("ACCTRANS_ACCOUNT");
        queryRequest.setBizModel(model);
        AlipayFundAccountQueryResponse response = alipayClient.certificateExecute(queryRequest);
        String body = response.getBody();
        log.info(body);
        if (!response.isSuccess()) {
            log.info("调用失败");
            return Result.Error(States.ERR_UNKNOWN);
        } else {
            BigDecimal busBalance = new BigDecimal(response.getAvailableAmount());
            BalanceAccountDTO balanceAccountDTO = iAssetServiceApi.selectBalanceAccountById(balanceAccountId);
            log.info(String.valueOf(balanceAccountDTO));
            if (balanceAccountDTO == null) {
                log.info("调用失败  ");
                return Result.Error(States.ERR_SELECT);
            } else {
                BigDecimal userBalance = balanceAccountDTO.getBalance();
                if (busBalance.compareTo(userBalance) == -1) {
                    log.info("调用失败");
                    return Result.Error(States.ERR_INTERNAL_SERVER_ERROR);
                } else {
                    String identity = balanceAccountDTO.getIdentity();
                    //获取用户类型
                    String identityType = balanceAccountDTO.getIdentityType();
                    //获取订单号
                    String outTradeNo = generateTradeNo();
                    AlipayFundTransUniTransferRequest transferRequest = new AlipayFundTransUniTransferRequest();
                    AlipayFundTransUniTransferModel transferModel = new AlipayFundTransUniTransferModel();
                    transferModel.setOutBizNo(outTradeNo);
                    transferModel.setTransAmount(transAmount);
                    transferModel.setProductCode("TRANS_ACCOUNT_NO_PWD");
                    transferModel.setBizScene("DIRECT_TRANSFER");
                    transferModel.setOrderTitle("环绿回收提现到用户支付宝");


                    Participant payeeInfo = new Participant();
                    payeeInfo.setIdentity(identity);
                    payeeInfo.setIdentityType(identityType);

                    transferModel.setPayeeInfo(payeeInfo);
                    transferRequest.setBizModel(transferModel);
                    AlipayFundTransUniTransferResponse transferResponse = alipayClient.certificateExecute(transferRequest);
                    log.info(transferResponse.getBody());
                    if (!transferResponse.isSuccess()) {
                        log.info("转账失败");
                        return Result.Error(States.ERR_INTERNAL_SERVER_ERROR);
                    } else {
                        log.info("转账成功");
                        BigDecimal operateBalanceNum = new BigDecimal(transAmount);
                        OperateBalanceRecordingDTO operateBalanceRecordingDTO = new OperateBalanceRecordingDTO();
                        operateBalanceRecordingDTO.setBalanceAccountId(Long.valueOf(balanceAccountId));
                        operateBalanceRecordingDTO.setOperate("环绿回收提现到用户支付宝");
                        operateBalanceRecordingDTO.setOperateBalanceNum(operateBalanceNum);
                        operateBalanceRecordingDTO.setGenerateTradeNo(generateTradeNo());
                        operateBalanceRecordingDTO.setTime(LocalDateTime.now());
                        int i = iAssetServiceApi.updateByBalance(operateBalanceRecordingDTO);
                        log.info("受影响的行数"+i);
                        if (i == 0){
                            log.info("插入失败");
                            return Result.Error(States.ERR_UPDATE);
                        }
                    }

                }
            }

        }
        return Result.OK();
    }

    @Override
    public Result recharge(BigDecimal money, int balanceAccountId,HttpServletResponse httpResponse) throws AlipayApiException {

        log.info("登录的用户id为:" + balanceAccountId);
        String outTradeNo = generateTradeNo();
        String form = "";

        AlipayClient alipayClient = new DefaultAlipayClient(getCertAlipayRequest());
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        //设置异步请求地址
        request.setNotifyUrl("http://k84htz.natappfree.cc/Alipay/AlipayNotify");
        //设置回调地址
        request.setReturnUrl("http://k84htz.natappfree.cc/explore");
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no",outTradeNo);
        bizContent.put("total_amount",money);
        bizContent.put("subject","用户支付宝充值到环绿回收账户");
        bizContent.put("product_code","FAST_INSTANT_TRADE_PAY");

        request.setBizContent(bizContent.toString());
        AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
        if (!response.isSuccess()){
            log.info("调用失败");
            return Result.Error(States.ERR_UNKNOWN);
        }else{
            log.info("调用成功");
            form = response.getBody();

            httpResponse.setContentType( "text/html;charset="+"utf-8");
            try {
                httpResponse.getWriter().write(form); //直接将完整的表单html输出到页面
                httpResponse.getWriter().flush();
                httpResponse.getWriter().close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return Result.OK();
    }

    @Override
    public String notify(HttpServletRequest request){
        //目前是写死的状态
        long balanceAccountId = Long.parseLong(request.getSession().getId());
//        long balanceAccountId = 5L;
        String tradeStatus = "TRADE_SUCCESS";

        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            // 乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }

        String trade_status = params.get("trade_status");
        String subject = params.get("subject");
        BigDecimal operateBalanceNum=new BigDecimal(params.get("total_amount"));
        String outTradeNo = params.get("out_trade_no");
        OperateBalanceRecordingDTO operateBalanceRecordingDTO = new OperateBalanceRecordingDTO();
        if (!trade_status.equals(tradeStatus)) {
            log.info("用户充值不成功");
            return "error";
        }else {
            operateBalanceRecordingDTO.setBalanceAccountId(balanceAccountId);
            operateBalanceRecordingDTO.setOperate(subject);
            operateBalanceRecordingDTO.setOperateBalanceNum(operateBalanceNum);
            operateBalanceRecordingDTO.setTime(LocalDateTime.now());
            operateBalanceRecordingDTO.setGenerateTradeNo(outTradeNo);
            int i = iAssetServiceApi.updateByBalance(operateBalanceRecordingDTO);
            if (i==0){
                log.info("充值信息插入失败");
                return "error";
        }
    }
        log.info("用户信息插入成功");
        return "success";
}



    /**
     * 通过时间生成外部订单号 out_trade_no
     *
     * @return
     */
    private String generateTradeNo() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String tradeNo = LocalDateTime.now(ZoneOffset.of("+8")).format(formatter);
        log.info("外部订单号:{}", tradeNo);
        return tradeNo;
    }
}